package com.polaris.live.widget

import android.content.Context
import android.graphics.Point
import android.util.AttributeSet
import com.blankj.utilcode.util.ConvertUtils
import com.polaris.live.R
import com.google.android.material.imageview.ShapeableImageView

/**
 * 以宽计算比例的ImageView
 *
 * @author Created by lucas on 2023/10/22 18:37
 * @since 1.0.0
 */
class ScaleImageView(context: Context, attrs: AttributeSet? = null) : ShapeableImageView(context, attrs) {

    private var mWidth = 0
    private var mHeight = 0
    private var mMaxSize = 0
    private var mMinSize = 0
    private var mInsideSize = 0
    private var mType = TYPE_CROP
    private var mPoint = Point()

    init {
        initAttrs(attrs)
        initView()
    }

    private fun initAttrs(attrs: AttributeSet?) {
        if (attrs == null) {
            return
        }
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScaleImageView)
        mType = typedArray.getInt(R.styleable.ScaleImageView_type, TYPE_CROP)
        typedArray.recycle()
    }

    private fun initView() {
        adjustViewBounds = true
        scaleType = if (mType == TYPE_CROP || mType == TYPE_INSIDE) {
            ScaleType.CENTER_INSIDE
        } else {
            ScaleType.FIT_XY
        }
        setOverride(maxWidth, minimumWidth)
        setInsideOverride(maxHeight)
    }

    fun getSize(): Pair<Int, Int> {
        return mWidth to mHeight
    }

    fun setSize(point: Point) {
        setSize(point.x, point.y)
    }

    fun setSize(width: Int, height: Int) {
        mWidth = width
        mHeight = height
        requestLayout()
    }

    fun setOverride(maxSize: Int, minSize: Int) {
        var maxSize = maxSize
        var minSize = minSize
        mMaxSize = maxSize
        mMinSize = minSize
        if (minSize > maxSize) {
            val temp = minSize
            minSize = maxSize
            maxSize = temp
        }
        if (maxSize == 0 && minSize == 0) {
            mMaxSize = DEFAULT_MAX_SIZE
            mMinSize = DEFAULT_MIN_SIZE
        }
    }

    fun setInsideOverride(maxSize: Int) {
        mInsideSize = maxSize
        if (maxSize == 0) {
            mInsideSize = DEFAULT_INSIDE_SIZE
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (mWidth == 0 || mHeight == 0) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            return
        } else if (mMaxSize == -1 && mMinSize == -1) {
            setMeasuredDimension(mWidth, mHeight)
            return
        }
        val point = calculateSize(mPoint)
        setMeasuredDimension(point.x, point.y)
    }

    private fun calculateSize(): Point {
        val point = Point()
        return try {
            calculateSize(point)
        } catch (e: ArithmeticException) {
            point
        }
    }

    private fun calculateSize(point: Point): Point {
        if (mWidth == 0 || mHeight == 0) {
            point.x = 0
            point.y = 0
            return point
        }
        var w: Int
        var h: Int
        if (mType == TYPE_CROP) {
            if (mWidth < mHeight) {
                w = if (mWidth < mMinSize) {
                    mMinSize
                } else if (mWidth > mMaxSize) {
                    mMaxSize
                } else {
                    mWidth
                }
                h = w * mHeight / mWidth
            } else {
                h = if (mHeight < mMinSize) {
                    mMinSize
                } else if (mHeight > mMaxSize) {
                    mMaxSize
                } else {
                    mHeight
                }
                w = h * mWidth / mHeight
            }
            val maxScale = mMaxSize / mMinSize.toFloat()
            if (w > h) {
                val srcScale = w / h.toFloat()
                if (srcScale > maxScale) {
                    w = (h * maxScale).toInt()
                }
            } else {
                val srcScale = h / w.toFloat()
                if (srcScale > maxScale) {
                    h = (w * maxScale).toInt()
                }
            }
        } else {
            if (mWidth > mHeight) {
                w = if (mWidth < mMinSize) {
                    mMinSize
                } else if (mWidth > mMaxSize) {
                    mMaxSize
                } else {
                    mWidth
                }
                h = w * mHeight / mWidth
            } else {
                h = if (mHeight < mMinSize) {
                    mMinSize
                } else if (mHeight > mMaxSize) {
                    mMaxSize
                } else {
                    mHeight
                }
                w = h * mWidth / mHeight
            }
            if (mType == TYPE_INSIDE) {
                if (w > h) {
                    if (h < mMinSize) {
                        w = mMinSize * w / h
                        h = mMinSize
                    }
                    if (w > mInsideSize) {
                        w = mInsideSize
                    }
                } else {
                    if (w < mMinSize) {
                        h = mMinSize * h / w
                        w = mMinSize
                    }
                    if (h > mInsideSize) {
                        h = mInsideSize
                    }
                }
            }
        }
        point.x = w
        point.y = h
        return point
    }

    companion object {

        val DEFAULT_MAX_SIZE = ConvertUtils.dp2px(120f)
        val DEFAULT_MIN_SIZE = ConvertUtils.dp2px(80f)
        val DEFAULT_INSIDE_SIZE = ConvertUtils.dp2px(200f)

        const val TYPE_CROP = 0
        const val TYPE_FIT = 1
        const val TYPE_INSIDE = 2
    }
}